//
//  DXMLTimeStamp.m
//  DerbyStatter
//
//  Created by glenn andreas on 1/29/14.
//  Copyright (c) 2014 glenn andreas. All rights reserved.
//

#import "DXMLTimeStamp.h"
#import "DXMLPeriodObject.h"
#import "DXMLJamObject.h"
#import "DXMLSkaterEventObject.h"
@implementation DXMLTimestamp
- (id) initWithString:(NSString *)value forObject: (DXMLObject *) object;
{
    if ([value rangeOfString:@"~"].location != NSNotFound) {
        // we have an estimated value
        NSArray *range = [value componentsSeparatedByString:@"~"];
        NSString *firstEstStr = [range objectAtIndex:0];
        NSString *secondEstStr = [range objectAtIndex:1];
        DXMLTimestamp *firstEst = [[DXMLTimestamp alloc] initWithString:firstEstStr forObject:object];
        DXMLTimestamp *secondEst = [[DXMLTimestamp alloc] initWithString:secondEstStr forObject:object];
        if (firstEst && secondEst) {
            DXMLRangeTimestamp *retval = [[DXMLRangeTimestamp alloc] initWithString:value];
            retval.earliestTime = firstEst;
            retval.latestTime = secondEst;
            return retval;
        }
        if (secondEst) {
            DXMLEstimateTimestamp *retval = [[DXMLEstimateTimestamp alloc] initWithString:value];
            retval.bestGuess = firstEst;
        }
        if (firstEst) {
            // something malformed like "5~" which we treat "5"
            return firstEst;
        }
        return nil; // neither side of ~ was value, so bogus
    }
    // WFTDA date value
    if ([value rangeOfString:@"^[1-2][0-9][0-9][0-9]_[0-9][0-9]_[0-9][0-9]$" options:NSRegularExpressionSearch].location != NSNotFound) {
        return [[DXMLAbsoluteTimestamp alloc] initWithString:value ];
    }

    if ([value rangeOfString:@"^(([0-1][1-9])|(2[0-3])):[0-5][0-9]:[0-5][0-9]$" options:NSRegularExpressionSearch].location != NSNotFound) {
        NSArray *parts = [value componentsSeparatedByString:@":"];
        NSDateComponents *compo = [[NSDateComponents alloc] init];
        compo.year = [[parts objectAtIndex:0] integerValue];
        compo.month = [[parts objectAtIndex:1] integerValue];
        compo.day = [[parts objectAtIndex:2] integerValue];
        NSDate *date = [[NSCalendar currentCalendar] dateFromComponents:compo];
        // pretend it was in absolute time, but fix string in post
        DXMLTimestamp *retval = [[DXMLAbsoluteTimestamp alloc] initWithString:[NSString stringWithFormat:@"%g",date.timeIntervalSince1970]];
        retval->_timestampValue = value;
        return retval;
    }

    if ([value rangeOfString:@"^(([0-1][1-9])|(2[0-3])):[0-5][0-9]:[0-5][0-9]$" options:NSRegularExpressionSearch].location != NSNotFound) {
        return [[DXMLAbsoluteTimestamp alloc] initWithString:value forObject:object];
    }
    if ([value rangeOfString:@"^[0-9]+$" options:NSRegularExpressionSearch].location != NSNotFound) {
        // either an absolute epoch based one, or period time relative
        if (object) {
            return [[DXMLPeriodRelativeTimestamp alloc] initWithString:value forObject:object];
        } else {
            return [[DXMLAbsoluteTimestamp alloc] initWithString:value]; // epoch based
        }
    }
    if ([value rangeOfString:@"^[0-5][0-9]:[0-5][0-9]$" options:NSRegularExpressionSearch].location != NSNotFound) {
        return [[DXMLPeriodClockTimestamp alloc] initWithString:value forObject:object];
    }
    if ([value rangeOfString:@"^[+^-][0-9]+$" options:NSRegularExpressionSearch].location != NSNotFound) {
        return [[DXMLJamRelativeTimestamp alloc] initWithString:value forObject:object];
    }
    return nil;
}
- (id) initWithString:(NSString *)value
{
    self = [super init];
    if (self) {
        _timestampValue = value;
    }
    return self;
}
- (NSTimeInterval) periodTime: (DXMLPeriodObject *) period // this counts up...
{
    return self.date.timeIntervalSinceReferenceDate - period.timestamp.date.timeIntervalSinceReferenceDate;
}
- (NSTimeInterval) jamTime: (DXMLJamObject *) jam
{
    return self.date.timeIntervalSinceReferenceDate - jam.timestamp.date.timeIntervalSinceReferenceDate;
}
- (BOOL) isEstimate
{
    return NO;
}
- (NSDate *) date
{
    return nil;
}

@end


@implementation DXMLAbsoluteTimestamp
@synthesize date = _date;
- (id) initWithString:(NSString *)value forObject: (DXMLObject *) object
{
    self = [super initWithString:value];
    if (self) {
        // Find the day for this HH:MM:SS
        // don't get object.closestTimestamp, that's what we are making now
        DXMLTimestamp *relative = [object.parent closestTimestamp];
        NSDate *day = [relative date];
        if (!day) day = [NSDate date]; // today
        _calendar = [NSCalendar currentCalendar];
        _timeZone = [NSTimeZone systemTimeZone];
#ifdef NSCalendarUnitHour
        NSDateComponents *comp = [_calendar components:NSCalendarUnitEra | NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay fromDate:day];
#else
        NSDateComponents *comp = [_calendar components:NSEraCalendarUnit | NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit fromDate:day];
#endif
        // parse out HH:MM:SS
        NSArray *parts = [value componentsSeparatedByString:@":"];
        comp.hour = [[parts objectAtIndex:0] integerValue];
        comp.minute = [[parts objectAtIndex:1] integerValue];
        comp.second = [[parts objectAtIndex:2] integerValue];
        _date = [_calendar dateFromComponents:comp];
    }
    return self;
}
- (id) initWithString:(NSString *)value
{
    self = [super initWithString:value];
    if (self) {
        _calendar = [NSCalendar currentCalendar];
        _timeZone = [NSTimeZone systemTimeZone];
        _date = [NSDate dateWithTimeIntervalSince1970:[value doubleValue]];
    }
    return self;
}
- (id) init
{
    NSDate *date = [NSDate date];
    self = [super initWithString:[NSString stringWithFormat:@"%g",[date timeIntervalSince1970]]];
    if (self) {
        _calendar = [NSCalendar currentCalendar];
        _timeZone = [NSTimeZone systemTimeZone];
        _date = date;
    }
    return self;
}
@end

@implementation DXMLPeriodRelativeTimestamp
- (id) initWithString:(NSString *)value forObject:(DXMLObject *)object
{
    self = [super initWithString:value];
    if (self) {
        _relativeTime = [value doubleValue];
        _period = [(DXMLJamObject *)object period];
    }
    return self;
}
- (NSDate *) date
{
    if (self.relativeTime >= 0) {
        return [self.period.timestamp.date dateByAddingTimeInterval:self.relativeTime];
    } else {
        return [self.period.periodEnd.date dateByAddingTimeInterval:self.relativeTime];
    }
}
- (NSTimeInterval) periodTime: (DXMLPeriodObject *) period // this counts up...
{
    if (period == self.period) {
        if (self.relativeTime >= 0)
            return self.relativeTime;
        return 0;
    }
    return [super periodTime:period];
}
@end

@implementation DXMLPeriodClockTimestamp
- (id) initWithString:(NSString *)value forObject:(DXMLObject *)object
{
    self = [super initWithString:value];
    if (self) {
        NSArray *parts = [value componentsSeparatedByString:@":"];
        _periodClock = [[parts objectAtIndex:0] integerValue];
        _periodClock = [[parts objectAtIndex:1] integerValue];
        _period = [(DXMLJamObject *)object period];
    }
    return self;
}
- (NSDate *) date
{
    return [self.period.timestamp.date dateByAddingTimeInterval:self.periodClock];
}
- (NSTimeInterval) periodTime: (DXMLPeriodObject *) period // this counts up...
{
    if (period == self.period) {
        return self.periodClock;
    }
    return [super periodTime:period];
}
@end

@implementation DXMLJamRelativeTimestamp
- (id) initWithString:(NSString *)value forObject:(DXMLObject *)object
{
    self = [super initWithString:value];
    if (self) {
        _jam = [(DXMLSkaterEventObject *)object jam];
        _relativeTime = [value doubleValue];
    }
    return self;
}
@end


@implementation DXMLEstimateTimestamp
- (NSDate *) date
{
    return self.bestGuess.date;
}
@end

@implementation DXMLRangeTimestamp
- (NSDate *) date
{
    if (self.bestGuess)
        return self.bestGuess.date;
    // use halfway between the two
    NSDate *date1 = self.earliestTime.date;
    NSDate *date2 = self.latestTime.date;
    return [NSDate dateWithTimeIntervalSinceReferenceDate:([date1 timeIntervalSinceReferenceDate] + [date2 timeIntervalSinceReferenceDate]) / 2];
}
@end